{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "4f49fdc8",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "# Demo: Estimating Option Price Using Amplitude Estimation\n",
    "\n",
    "## Introduction and background\n",
    "\n",
    "#\n",
    "\n",
    "In Finance models we are often interested in calculating the average of a function of a given probability distribution ($E[f(x)]$). The most popular method to estimate the average is Monte Carlo [[1](#MCMF)] due to its flexibility and ability to generically handle stochastic parameters.\n",
    "Classical Monte Carlo methods, however, generally require extensive computational resources to provide an accurate estimation.\n",
    "By leveraging the laws of quantum mechanics, a quantum computer may provide novel ways to\n",
    "solve computationally intensive financial problems, such as risk management, portfolio optimization, and option pricing.\n",
    "The core quantum advantage of several of these applications is the Amplitude Estimation algorithm [[2](#AEA)] which can estimate a parameter with a\n",
    "convergence rate of $\\Omega(1/M^{1/2})$, compared to $\\Omega(1/M)$ in the classical case, where $M$ is the number of Grover iterations in the quantum case and the number of the Monte Carlo samples in the classical case. This represents a theoretical quadratic speed-up of the quantum method over classical Monte Carlo methods.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "731ba399",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "### Option pricing\n",
    "\n",
    "An option is the possibility to buy (call) or sell (put) an item (or share) at a known price - the strike price (K), where the option has a maturity price (S).\n",
    "The payoff function to describe for example a European call option will be:\n",
    "\n",
    "$f(S)=\\\n",
    "\\Bigg\\{\\begin{array}{lr}\n",
    "    0, & \\text{when } K\\geq S\\\\\n",
    "    S - K, & \\text{when } K < S\\end{array}\n",
    "$\n",
    "\n",
    "The maturity price is unknown. Therefore, it is expressed by a price distribution function, which may be any type of a distribution function.\n",
    "For example a log-normal distribution: $\\mathcal{ln}(S)\\sim~\\mathcal{N}(\\mu,\\sigma)$,\n",
    "where $\\mathcal{N}(\\mu,\\sigma)$ is the standard normal distribution with mean equal to $\\mu$ and sdt equal to $\\sigma$ .\n",
    "\n",
    "To estimate the average option price using a quantum computer, one needs to:\n",
    "\n",
    "- Load the distribution, that is, discretize the distribution using $2^n$ points (n is the number of qubits) and truncate it.\n",
    "\n",
    "- Implement the payoff function that is equal to zero if $S\\leq{K}$ and increases linearly otherwise.\n",
    "  The linear part is approximated in order to be loaded properly using $R_y$ rotations [[3](#QAR)].\n",
    "\n",
    "- Evaluate the expected payoff using amplitude estimation\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "397b9839",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "### The probability distribution\n",
    "\n",
    "We begin by creating the probability distribution. We use `FinanceModelInput`, to build discrete version of the log normal probability with $2^n$ points, when $\\mu$ is equal to `mu`, $\\sigma$ is equal to `sigma` and $n$ is equal to `num_qubits`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "b1e0e51a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T15:05:47.873084Z",
     "iopub.status.busy": "2024-05-07T15:05:47.872524Z",
     "iopub.status.idle": "2024-05-07T15:05:50.814964Z",
     "shell.execute_reply": "2024-05-07T15:05:50.814311Z"
    },
    "pycharm": {
     "name": "#%%\n"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from classiq.applications.finance import log_normal_model_input\n",
    "\n",
    "num_qubits = 5\n",
    "mu = 0.7\n",
    "sigma = 0.13\n",
    "\n",
    "log_normal_model = log_normal_model_input.LogNormalModelInput(\n",
    "    num_qubits=num_qubits, mu=mu, sigma=sigma\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c8635919",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "### The option pricing function\n",
    "\n",
    "We continue with creating the option pricing function . We use `FinanceFunctionInput`, to build the European call option function, when $K$ equal to `threshold`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "986b9ce8",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T15:05:50.818471Z",
     "iopub.status.busy": "2024-05-07T15:05:50.817533Z",
     "iopub.status.idle": "2024-05-07T15:05:50.821790Z",
     "shell.execute_reply": "2024-05-07T15:05:50.821197Z"
    },
    "pycharm": {
     "name": "#%%\n"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from classiq.applications.finance import function_input\n",
    "\n",
    "threshold = 1.9\n",
    "\n",
    "condition = function_input.FunctionCondition(threshold=threshold, larger=True)\n",
    "finance_function = function_input.FinanceFunctionInput(\n",
    "    f=\"european call option\",\n",
    "    condition=condition,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bbb7834c",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "### Loading the model\n",
    "\n",
    "After defining the probability distribution and the finance function input, we proceed by creating a Model. The Model define the logic flow of the quantum algorithm. In this case, the logic flow includes one `Finance` operator that loads the distribution and then implements the payoff function, which is plugged into the amplitude estimation algorithm (using phase estimation). We need to define the number of qubits used by the phase estimation algorithm which will set the accuracy of the calculation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "bd2d44b5",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T15:05:50.824175Z",
     "iopub.status.busy": "2024-05-07T15:05:50.823868Z",
     "iopub.status.idle": "2024-05-07T15:05:50.832375Z",
     "shell.execute_reply": "2024-05-07T15:05:50.831756Z"
    },
    "pycharm": {
     "name": "#%%\n"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from classiq import construct_finance_model\n",
    "\n",
    "qmod = construct_finance_model(\n",
    "    finance_model_input=log_normal_model,\n",
    "    finance_function_input=finance_function,\n",
    "    phase_port_size=2,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7956ead5-7f2a-4a3e-b4d7-06c5c3b676ac",
   "metadata": {
    "tags": []
   },
   "source": [
    "### Setting Constraints to the circuit"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "86857325-b6b0-4c04-b5e0-eba6c491a9c6",
   "metadata": {},
   "source": [
    "We set constraints for the number of qubits in order to get an optimized quantum circuit."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "68e347e3-626b-4c95-b6f9-9ca54de0b7e6",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T15:05:50.834971Z",
     "iopub.status.busy": "2024-05-07T15:05:50.834574Z",
     "iopub.status.idle": "2024-05-07T15:05:50.844738Z",
     "shell.execute_reply": "2024-05-07T15:05:50.844045Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from classiq import Constraints\n",
    "from classiq.synthesis import set_constraints\n",
    "\n",
    "qmod = set_constraints(qmod, constraints=Constraints(max_width=20))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "6cd58adc-4cc0-4030-9458-7b295b6f4f0d",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T15:05:50.847388Z",
     "iopub.status.busy": "2024-05-07T15:05:50.846871Z",
     "iopub.status.idle": "2024-05-07T15:05:50.856583Z",
     "shell.execute_reply": "2024-05-07T15:05:50.855997Z"
    }
   },
   "outputs": [],
   "source": [
    "from classiq import write_qmod\n",
    "\n",
    "write_qmod(qmod, \"option_pricing\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7fd2f677",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "### Synthesizing the circuit\n",
    "\n",
    "Now we are ready to synthesize the circuit using Classiq's synthesis engine. The synthesis should take approximately several seconds:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "b74362c6-0045-4480-b6e7-306dcf2df559",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T15:05:50.859275Z",
     "iopub.status.busy": "2024-05-07T15:05:50.858761Z",
     "iopub.status.idle": "2024-05-07T15:05:59.456437Z",
     "shell.execute_reply": "2024-05-07T15:05:59.455637Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from classiq import synthesize\n",
    "\n",
    "qprog = synthesize(qmod)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f44e6bd9",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "### Showing the Resulting Circuit\n",
    "\n",
    "After Classiq's synthesis engine has finished the job, we can show the resulting circuit in the interactive GUI:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "bfa45eb6-5ff3-46c9-a292-ca9f9c605e0b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T15:05:59.460069Z",
     "iopub.status.busy": "2024-05-07T15:05:59.459818Z",
     "iopub.status.idle": "2024-05-07T15:05:59.650023Z",
     "shell.execute_reply": "2024-05-07T15:05:59.649266Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Opening: https://platform.classiq.io/circuit/61aad498-f6fd-43f8-8462-fd48b9753de4?version=0.41.0.dev39%2B79c8fd0855\n"
     ]
    }
   ],
   "source": [
    "from classiq import QuantumProgram, show\n",
    "\n",
    "show(qprog)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "e5c43f39",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T15:05:59.658135Z",
     "iopub.status.busy": "2024-05-07T15:05:59.653455Z",
     "iopub.status.idle": "2024-05-07T15:05:59.693900Z",
     "shell.execute_reply": "2024-05-07T15:05:59.693190Z"
    },
    "pycharm": {
     "name": "#%%\n"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2593\n"
     ]
    }
   ],
   "source": [
    "circuit = QuantumProgram.from_qprog(qprog)\n",
    "print(circuit.transpiled_circuit.depth)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cf831b22",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "### Executing the circuit\n",
    "\n",
    "Lastly, we can execute the resulting circuit with Classiq's execute interface, using the `execute` function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "3c927939-f26d-4a71-bfac-4b89c6ba603e",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T15:05:59.699670Z",
     "iopub.status.busy": "2024-05-07T15:05:59.698290Z",
     "iopub.status.idle": "2024-05-07T15:06:03.361082Z",
     "shell.execute_reply": "2024-05-07T15:06:03.360296Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from classiq import execute\n",
    "\n",
    "results = execute(qprog).result()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bafef6e4",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Printing out the result estimation of the options price :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "3b4c29f4-ff42-4120-a6e1-f7b0362bfe6c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T15:06:03.364805Z",
     "iopub.status.busy": "2024-05-07T15:06:03.364317Z",
     "iopub.status.idle": "2024-05-07T15:06:03.369397Z",
     "shell.execute_reply": "2024-05-07T15:06:03.368663Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "estimation : 0.37948482165243613\n"
     ]
    }
   ],
   "source": [
    "print(results[1].name, \":\", results[1].value)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2aacb5d2",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "## References\n",
    "\n",
    "<a name='MCMF'>[1]</a>: [Paul Glasserman, Monte Carlo Methods in Financial Engineering. Springer-Verlag New York, 2003, p. 596.](https://link.springer.com/book/10.1007/978-0-387-21617-1)\n",
    "<br><a name='AEA'>[2]</a>: [Gilles Brassard, Peter Hoyer, Michele Mosca, and Alain Tapp, Quantum Amplitude Amplification and Estimation. Contemporary Mathematics 305 (2002)](https://arxiv.org/abs/quant-ph/0005055)\n",
    "<br><a name='QAR'>[3]</a>: [ Nikitas Stamatopoulos, Daniel J. Egger, Yue Sun, Christa Zoufal, Raban Iten, Ning Shen, and Stefan Woerner, Option Pricing using Quantum Computers, Quantum 4, 291 (2020).\n",
    "](https://arxiv.org/abs/1905.02666v5)\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.9"
  },
  "vscode": {
   "interpreter": {
    "hash": "a07aacdcc8a415e7643a2bc993226848ff70704ebef014f87460de9126b773d0"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
